package graph

import (
  "container/vector";
  "json";
  "math";
  "fmt";
)

const (
  DEBUG = false;
)
func dbg(x ...) { if DEBUG {fmt.Println(x)} }


// in several places float64 is used to suit the math package where float would be better
type Vertex struct {
  Name string; // display name for this vertex
  Adjacent map [string] (*Vertex); // adjacent vertices, notice names must be unique
  Cost float64; // minimum total cost from starting vertex to this one
  
  x float;
  y float;
  
  // barnacles
  Bfs *bfsBarn;
}


// New creates a Vertex.
func NewVertex(name string, cost float64, adjacent map [string] *Vertex) *Vertex {
  if adjacent == nil {
    adjacent = make(map [string] *Vertex);
  }
  
  v := Vertex{name, adjacent, cost, 0,0, nil};
	return &v;
}

type Edge struct {
  Name string; // display name for this vertex
  Src *Vertex; // the start vertex of this edge
  Dest *Vertex; // the destination of this edge
  Cost float64; // minimum total cost from starting vertex to this one
}

func NewEdge(name string, cost float64, src Vertex, dest Vertex) *Edge {
  e := Edge{name, &src, &dest, cost};
  return &e;
}

type Graph struct {
  Name string;
  vertexMap map [string] (*Vertex);
  edgeMap map [string] Edge; // probably redundant
}

func (g *Graph) Init() {
  g.vertexMap = make(map[string](*Vertex));
  g.edgeMap = make(map[string]Edge);
}

func (g *Graph) GoString() string {
  s := g.Name + "\n";
  for name, edge := range(g.edgeMap) {
    s += name + ": " + edge.Src.Name + " - " + edge.Dest.Name + "\n";
  }

  return s;
}

// retrieve a vertex from the graph by name
// if the vertex doesn't exist then it's added
func (g Graph) GetVertex(name string) (v *Vertex) {
  dbg("GetVertex");
  var present bool;
  vo, present := g.vertexMap[name];
  if (!present) {
    v = NewVertex(name, math.Inf(1), nil);
    g.vertexMap[name] = v;
  } else {
    v = vo;
  }
  return;
}

// retrieve an edge from the graph by name
// if the edge doesn't exist then it's added
func (g Graph) PutEdge(e *Edge) {
  name := e.Src.Name + e.Dest.Name;
  dbg("PutEdge ",name);
  _, present := g.edgeMap[name];
  // edges are treated as directed
  e.Src.Adjacent[e.Dest.Name]=e.Dest;
  if (!present) {
    g.edgeMap[name] = *e;
  } else {
    // replace it?
  }
  
  return;
}


// GraphBuilder implements the json.Builder interface
// if the config gets more complex then we can split it in to
// several separate Builders (like one for the Edges array,
// one for the Graph object, etc.)
type ConfBuilder struct {
  Graphs vector.Vector; // a collection of graphs read from the json file
  e *Edge; // current edge
  i	int;
  k	string;
  waitingFor int;
}

func (b *ConfBuilder) GoString() string {
  return b.Show();
}


func (b *ConfBuilder) Show() (s string) {
  s = "Config:\n";
  for graph := range b.Graphs.Iter() {
    s += ":: " + graph.(*Graph).Name + ":: " + graph.(*Graph).GoString() + "\n";
  }
  return s;
}

// states
const (
  TOKEN_NONE = iota;
  TOKEN_NAME;
  TOKEN_SOURCE;
  TOKEN_DEST;
  TOKEN_COST;
)

func (b *ConfBuilder) Init() {
  //b.Graphs = new(vector.Vector);
}

func (b *ConfBuilder) Float64(f float64)	{
  dbg(f);
}

func (b *ConfBuilder) Int64(i int64)	  { dbg(float64(i)); }
func (b *ConfBuilder) Uint64(i uint64)	{ dbg(float64(i)); }
func (b *ConfBuilder) Bool(tf bool)	    { dbg(tf); }
func (b *ConfBuilder) Null()	          { dbg(""); }
func (b *ConfBuilder) String(s string)	{
  dbg("string: ",s);
}
func (b *ConfBuilder) Array()	{ fmt.Println("ConfBuilder Array"); }
func (b *ConfBuilder) Map()	{
  dbg("ConfBuilder Map");
}

func (b *ConfBuilder) Elem(i int) json.Builder {
  dbg("ConfBuilder Elem ",i);
  return b;
}

func (b *ConfBuilder) Key(k string) json.Builder {
  dbg("ConfBuilder Key: ", k);
	switch {
    case k == "graphs":
      b.k = k;
      gab := new(_graphsArrayBuilder);
      gab.parent = b;
      return gab;
  }
  return nil;
}

func (b *ConfBuilder) Flush()	{
  dbg("ConfBuilder Flush");
}

func NewConfBuilder() *ConfBuilder {
  return new(ConfBuilder);
}

type _graphsArrayBuilder struct {
  waitingFor int;
  g *Graph; // the graph we're currently processing
  k string;
  parent *ConfBuilder;
}

func (b *_graphsArrayBuilder) Float64(f float64){ dbg("_graphsArrayBuilder", f);}
func (b *_graphsArrayBuilder) Int64(i int64)	  { dbg("_graphsArrayBuilder", i);}
func (b *_graphsArrayBuilder) Uint64(i uint64)	{ dbg("_graphsArrayBuilder", i);}
func (b *_graphsArrayBuilder) Bool(tf bool)	    { dbg("_graphsArrayBuilder", tf);}
func (b *_graphsArrayBuilder) Null()	          { dbg("_graphsArrayBuilder", "null");}
func (b *_graphsArrayBuilder) String(s string)	{
  dbg("_graphsArrayBuilder", "string", s);
  return;
}

func (b *_graphsArrayBuilder) Array()	          { dbg("_graphsArrayBuilder", "array");}
func (b *_graphsArrayBuilder) Map()	            { dbg("_graphsArrayBuilder", "map");}
func (b *_graphsArrayBuilder) Elem(i int) (json.Builder) {
  dbg("_graphsArrayBuilder", "Elem", i);
  gb := new(_graphBuilder);
  gb.parent = b;
  return gb;
}

func (b *_graphsArrayBuilder) Key(k string) (json.Builder) {
  dbg("_graphsArrayBuilder", "key", k);
  return b;
}

func (b *_graphsArrayBuilder) Flush()	{
  dbg("_graphsArrayBuilder", "flush");
}

type _graphBuilder struct {
  waitingFor int;
  completeness int;
  k string;
  g *Graph; // the graph we're currently processing
  e *Edge;
  parent *_graphsArrayBuilder;
}

const (
  _GB_GOT_NAME = 1 << iota;
  _GB_GOT_EDGES;
  _GB_COMPLETE = _GB_GOT_NAME + _GB_GOT_EDGES;
)

func (b *_graphBuilder) Float64(f float64){ dbg("_graphBuilder", f);}
func (b *_graphBuilder) Int64(i int64)	  { dbg("_graphBuilder", i);}
func (b *_graphBuilder) Uint64(i uint64)	{ dbg("_graphBuilder", i);}
func (b *_graphBuilder) Bool(tf bool)	    { dbg("_graphBuilder", tf);}
func (b *_graphBuilder) Null()	          { dbg("_graphBuilder", "null");}
func (b *_graphBuilder) String(s string)	{
  dbg("_graphBuilder", "string", s);
  switch {
    case b.waitingFor==TOKEN_NAME:
      b.g.Name = s;
      b.waitingFor = TOKEN_NONE;
      b.completeness |= _GB_GOT_NAME;
  }
  return;
}

func (b *_graphBuilder) Array()	          {
  dbg("_graphBuilder", "array");
  
}

func (b *_graphBuilder) Map()	            {
  dbg("_graphBuilder", "map");
  // when Map is called we know we're actually going to get some data
  b.g = new(Graph);
  b.g.Init();
  // parent is the graphs array builder
  b.parent.parent.Graphs.Push(b.g);
}
  
func (b *_graphBuilder) Elem(i int) (json.Builder) {
  dbg("_graphBuilder", "Elem", i);
  return b;
}

func (b *_graphBuilder) Key(k string) (json.Builder) {
  dbg("_graphBuilder", "key", k);
	switch {
    case k == "name":
      b.k = k;
      b.waitingFor = TOKEN_NAME;  
      return b;
    case k == "edges":
      b.k = k;
      eab := new(_edgesArrayBuilder);
      eab.parent = b;
      return eab;
    default:
     return nil;
  }
  return nil;
}

func (b *_graphBuilder) Flush()	{
  dbg("_graphBuilder", "flush");
}


type _edgesArrayBuilder struct {
  waitingFor int;
  parent *_graphBuilder;
}

func (b *_edgesArrayBuilder) Float64(f float64)	{ dbg("_edgesArrayBuilder", f);}
func (b *_edgesArrayBuilder) Int64(i int64)	    { dbg("_edgesArrayBuilder", i);}
func (b *_edgesArrayBuilder) Uint64(i uint64)	  { dbg("_edgesArrayBuilder", i);}
func (b *_edgesArrayBuilder) Bool(tf bool)	    { dbg("_edgesArrayBuilder", tf);}
func (b *_edgesArrayBuilder) Null()	            { dbg("_edgesArrayBuilder", "null");}
func (b *_edgesArrayBuilder) String(s string)	  { dbg("_edgesArrayBuilder", "string", s);}
func (b *_edgesArrayBuilder) Array()	          { dbg("_edgesArrayBuilder", "array");}
func (b *_edgesArrayBuilder) Map()	            {
  dbg("_edgesArrayBuilder", "map");
  
}

func (b *_edgesArrayBuilder) Elem(i int) (json.Builder) {
  dbg("_edgesArrayBuilder", "Elem", i);
  eb := new(_edgeBuilder);
  eb.parent = b;
  eb.g = b.parent.g;
  return eb;
}

func (b *_edgesArrayBuilder) Key(k string) (json.Builder) {
  dbg("_edgesArrayBuilder", "key", k);
  return b;
}

func (b *_edgesArrayBuilder) Flush()	{
  dbg("_edgesArrayBuilder", "flush");
}

type _edgeBuilder struct {
  waitingFor int;
  completeness int;
  g *Graph; // the graph we're currently processing
  e *Edge;
  parent *_edgesArrayBuilder;
}

const (
  _EB_GOT_SRC = 1 << iota;
  _EB_GOT_DEST;
  _EB_GOT_COST;
  _EB_COMPLETE = _EB_GOT_SRC + _EB_GOT_DEST + _EB_GOT_COST;
)

func (b *_edgeBuilder) Float64(f float64)	{
  dbg("_edgeBuilder", f);
  switch {
    case b.waitingFor==TOKEN_COST:
      b.e.Cost = f;
      b.waitingFor = TOKEN_NONE;
      b.completeness |= _EB_GOT_COST;
  }
}

func (b *_edgeBuilder) Int64(i int64)	  {
  dbg("_edgeBuilder", "int64", i);
  b.Float64(float64(i));
}

func (b *_edgeBuilder) Uint64(i uint64)	{
  dbg("_edgeBuilder", "uint64", i);
  b.Float64(float64(i));
}

func (b *_edgeBuilder) Bool(tf bool)	    { dbg("_edgeBuilder", "bool", tf); }
func (b *_edgeBuilder) Null()	          { dbg("_edgeBuilder", "null"); }
func (b *_edgeBuilder) String(s string)	{
  dbg("_edgeBuilder", "string", s);
  switch {
    case b.waitingFor==TOKEN_SOURCE:
      b.e.Src = b.g.GetVertex(s);
      b.waitingFor = TOKEN_NONE;
      b.completeness |= _EB_GOT_SRC;
    case b.waitingFor==TOKEN_DEST:
      b.e.Dest = b.g.GetVertex(s);
      b.waitingFor = TOKEN_NONE;
      b.completeness |= _EB_GOT_DEST;
  }
  return;
}

func (b *_edgeBuilder) Array()	          { dbg("_edgeBuilder", "array"); }
func (b *_edgeBuilder) Map()	            {
  dbg("_edgeBuilder", "map");
  b.e = new(Edge);
}
  
func (b *_edgeBuilder) Elem(i int) (json.Builder) {
  dbg("_edgeBuilder", "Elem", i);
  return b;
}

func (b *_edgeBuilder) Key(k string) (json.Builder) {
  dbg("_edgeBuilder", "key", k);
  switch {
    case k == "source":
      b.waitingFor=TOKEN_SOURCE;
    case k == "dest":
      b.waitingFor=TOKEN_DEST;
    case k == "cost":
      b.waitingFor=TOKEN_COST;
  }
  return b;
}

func (b *_edgeBuilder) Flush()	{
  dbg("_edgeBuilder", "flush");
  if b.completeness == _EB_COMPLETE {
    b.g.PutEdge(b.e);
    dbg("complete edge: ", b.e);
    b.completeness = 0;
  } else {
    dbg("incomplete ", b.completeness," of ",_EB_COMPLETE);
  }
}

